package yf.mall.component.app;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Component;
import yf.mall.common.Const;
import yf.mall.dysdk.model.DyToken;
import yf.mall.dysdk.service.DyAuthService;
import yf.mall.dysdk.utils.DyUtil;
import yf.mall.entity.DyAccountAuthEntity;
import yf.mall.service.app.DyAccountAuthService;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Component
public class AppDyAuthCompoent {

    @Resource
    private DyAuthService dyAuthService;

    @Resource
    private DyAccountAuthService dyAccountAuthService;

    public DyToken getDefaultToken() {
        DyAccountAuthEntity defaultAuth = dyAccountAuthService.getDefaultToken();
        if (defaultAuth == null) {
            return null;
        }
        return convertToken(defaultAuth);
    }

    public DyToken getMasterTokenByUser(Long userId) {
        DyAccountAuthEntity accountAuthEntity = dyAccountAuthService.getMasterAuthByUserId(userId);
        if (accountAuthEntity == null) {
            return null;
        }
        if (isExpired(accountAuthEntity)) {
            refreshToken(accountAuthEntity);
        }

        return convertToken(accountAuthEntity);
    }

    public List<DyToken> getAllTokenByUser(Long userId) {
        List<DyAccountAuthEntity> accountAuthEntities = dyAccountAuthService.getAllAuthByUser(userId);
        if (accountAuthEntities.isEmpty()) {
            return Collections.emptyList();
        }
        return accountAuthEntities.stream().map(entity -> {
            return convertToken(entity);
        }).collect(Collectors.toList());
    }

    public DyToken getTokenByOpenId(String authorOpenid) {
        DyAccountAuthEntity dyAccountAuthEntity = dyAccountAuthService.getAuthByOpenId(authorOpenid);
        return convertToken(dyAccountAuthEntity);
    }

    public boolean refreshToken(DyAccountAuthEntity authEntity) {
        if (authEntity == null) {
            return false;
        }
        Date now = new Date();
        if (authEntity.getNextRenewRefreshTime().compareTo(now) < 0) {
            boolean result = renewRefreshToken(authEntity);
            if(result){
                return refreshToken(authEntity);
            }else{
                return false;
            }
        }
        DyToken dyToken = dyAuthService.refreshAccessToken(authEntity.getRefreshToken());
        if (dyToken == null) {
            return false;
        }
        if (dyToken.getErrorCode() == 10010) {
            return false;
        }
        if (dyToken.getErrorCode() != 0) {
            return false;
        }
        DyAccountAuthEntity refreshAuth = new DyAccountAuthEntity();
        refreshAuth.setUserId(authEntity.getUserId());
        refreshAuth.setOpenId(authEntity.getOpenId());
        refreshAuth.setAuthTime(new Date());
        refreshAuth.setAccessToken(dyToken.getAccessToken());
        refreshAuth.setExpiresIn(dyToken.getExpiresIn());
        refreshAuth.setNextRefreshTime(DateUtils.addSeconds(new Date(), dyToken.getExpiresIn()));
        return dyAccountAuthService.updateAuthToken(refreshAuth);
    }

    public boolean renewRefreshToken(DyAccountAuthEntity authEntity) {
        DyToken refreshToken = dyAuthService.refreshRefreshToken(authEntity.getRefreshToken());
        if (refreshToken == null || refreshToken.getErrorCode() != 0) {
            return false;
        }
        authEntity.setRefreshToken(refreshToken.getRefreshToken());
        authEntity.setRefreshExpiresIn(refreshToken.getExpiresIn());
        authEntity.setNextRenewRefreshTime(DateUtils.addSeconds(new Date(), refreshToken.getExpiresIn() - Const.DY_REFRESH_TOKEN_EARLIIER_SECOND));

        DyAccountAuthEntity refreshAuth = new DyAccountAuthEntity();
        refreshAuth.setUserId(authEntity.getUserId());
        refreshAuth.setOpenId(authEntity.getOpenId());
        refreshAuth.setRefreshToken(refreshToken.getRefreshToken());
        refreshAuth.setRefreshExpiresIn(refreshToken.getExpiresIn());
        // 默认是2592000，这里提前1小时刷新，以防止刷新的时候已过期
        refreshAuth.setNextRenewRefreshTime(DateUtils.addSeconds(new Date(), refreshToken.getExpiresIn() - Const.DY_REFRESH_TOKEN_EARLIIER_SECOND));
        return dyAccountAuthService.updateAuthToken(refreshAuth);
    }

    public static DyToken convertToken(DyAccountAuthEntity accountAuthEntity) {
        if (accountAuthEntity == null) {
            return null;
        }
        DyToken dyToken = new DyToken();
        dyToken.setAccessToken(accountAuthEntity.getAccessToken());
        dyToken.setExpiresIn(accountAuthEntity.getExpiresIn());
        dyToken.setOpenId(accountAuthEntity.getOpenId());
        dyToken.setRefreshExpiresIn(accountAuthEntity.getRefreshExpiresIn());
        dyToken.setRefreshToken(accountAuthEntity.getRefreshToken());
        dyToken.setScope(accountAuthEntity.getScope());
        return dyToken;
    }

    public static DyAccountAuthEntity convertAuth(Long userId, DyToken dyToken) {
        DyAccountAuthEntity authEntity = new DyAccountAuthEntity();
        authEntity.setUserId(userId);
        authEntity.setAccessToken(dyToken.getAccessToken());
        authEntity.setRefreshToken(dyToken.getRefreshToken());
        authEntity.setExpiresIn(dyToken.getExpiresIn());
        authEntity.setRefreshExpiresIn(dyToken.getRefreshExpiresIn());
        authEntity.setScope(dyToken.getScope());
        authEntity.setOpenId(dyToken.getOpenId());
        return authEntity;
    }

    public DyToken getDyTokenByUserIdAndDisplayId(Long userId, String displayId) {
        DyAccountAuthEntity dyAccountAuthEntity = dyAccountAuthService.getAuthByUserAndDisplayId(userId, displayId);
        if (dyAccountAuthEntity == null) {
            return null;
        }
        return convertToken(dyAccountAuthEntity);
    }

    private boolean isExpired(DyAccountAuthEntity accountAuthEntity) {
        return DyUtil.isExpired(accountAuthEntity.getAuthTime(), accountAuthEntity.getExpiresIn());
    }

}
